package leo.gptBot.dto.request;

import com.alibaba.fastjson2.annotation.JSONField;
import leo.gptBot.constant.ElementTypeEnum;
import leo.gptBot.constant.MessageHolderTypeEnum;
import leo.gptBot.constant.MessageTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.apache.logging.log4j.util.Strings;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author ：Leo
 * @date ：Created in 2024/7/22 14:38
 * @description：
 */
@Getter
public class Message implements Serializable{
    @JSONField(name = "post_type")
    private final String postType;

    @JSONField(name = "meta_event_type")
    private final String metaEventType;

    @JSONField(name = "message_type")
    private String messageType;

    @JSONField(name = "notice_type")
    private final String noticeType;

    // 操作人id 比如群管理员a踢了一个人,那么该值为a的qq号
    @JSONField(name = "operator_id")
    private final Long operatorId;

    @JSONField(name = "time")
    private final Long time;

    @JSONField(name = "self_id")
    private final Long selfId;

    @JSONField(name = "sub_type")
    private final String subType;

    @JSONField(name = "user_id")
    private final Long userId;

    @JSONField(name = "sender_id")
    private final Long senderId;

    @JSONField(name = "group_id")
    private final Long groupId;

    @JSONField(name = "target_id")
    private final Long targetId;

    @JSONField(name = "message")
    private final List<MessageHolder> message;

    @JSONField(name = "raw_message")
    private final String rawMessage;

    @JSONField(name = "font")
    private final Integer font;

    @JSONField(name = "sender")
    private final Sender sender;

    @JSONField(name = "message_id")
    private final String messageId;

    @JSONField(name = "message_seq")
    private final Integer messageSeq;

    @JSONField(name = "anonymous")
    private final String anonymous;

    @JSONField(name = "raw")
    private final Raw raw;

        public Message(String postType, String metaEventType, String messageType, String noticeType, Long operatorId,
                       Long time, Long selfId, String subType, Long userId, Long senderId, Long groupId, Long targetId,
                       List<MessageHolder> message, String rawMessage, Integer font, Sender sender, String messageId, Integer messageSeq, String anonymous,
                       Raw raw) {
            this.postType = postType;
            this.metaEventType = metaEventType;
            this.noticeType = noticeType;
            this.operatorId = operatorId;
            this.time = time;
            this.selfId = selfId;
            this.subType = subType;
            this.userId = userId;
            this.senderId = senderId;
            this.groupId = groupId;
            this.targetId = targetId;
            this.message = message;
            this.rawMessage = rawMessage;
            this.font = font;
            this.sender = sender;
            this.messageId = messageId;
            this.messageSeq = messageSeq;
            this.anonymous = anonymous;
            this.messageType = messageType;
            if(Strings.isBlank(this.messageType)){
                if(groupId != null){
                    this.messageType = MessageTypeEnum.group.getType();
                }else if(this.userId != null){
                    this.messageType = MessageTypeEnum.privat.getType();
                }
            }
            this.raw = raw;
        }


        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public static class Raw{
            private List<Element> elements;
            private List<Record> records;
        }

        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public static class MessageHolder{
            private String type;
            private MessageData data;
        }

        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public static class MessageData{
            // image
            private String file;
            private String url;
            private String fileSize;

            // reply
            private String id;

            // text
            private String text;
            // at
            private String qq;
        }

        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public static class Record{
            private String msgId;
            private String msgRandom;
            private Integer chatType;
            private Integer subMsgType;
            private String peerUid;
            private String sendMemberName;
            private List<Element> elements;
        }

        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public static class Element{
            private Integer elementType;
            private String elementId;
            private PicElement picElement;
            private ReplyElement replyElement;
            private TextElement textElement;

        }

        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public static class PicElement{
            private String fileName;
            private String sourcePath;
            private String fileSize;
            private Long picWidth;
            private Long picHeight;

        }
        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public static class ReplyElement{
            private String replayMsgId;
            private String replayMsgSeq;
            private String replayMsgRootSeq;
            private String replayMsgRootMsgId;
            private String sourceMsgIdInRecords;
            private String senderUid;
            private String replyMsgTime;

        }
        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public static class TextElement{
            private String content;
            private String atUid;
            private String atTinyId;
            private Integer atType;
            private String atRoleId;
            private String atRoleName;
            private Integer needNotify;

        }

        public boolean isGroupMsg(){
            return MessageTypeEnum.group.getType().equals(this.messageType);
        }

        public boolean isPrivateMsg(){
            return MessageTypeEnum.privat.getType().equals(this.messageType);
        }

        public boolean isReplyMsg(){
            if(!CollectionUtils.isEmpty(this.message)){
                return this.message.stream().map(MessageHolder::getType).toList().contains(MessageHolderTypeEnum.reply.name());
            }
            return false;
        }

        public boolean isPicMsg(){
            if(!CollectionUtils.isEmpty(this.message)){
                return this.message.stream().map(MessageHolder::getType).toList().contains(MessageHolderTypeEnum.image.name());
            }
            return false;
        }

        public boolean isTextMsg(){
            if(!CollectionUtils.isEmpty(this.message)){
                return this.message.stream().map(MessageHolder::getType).toList().contains(MessageHolderTypeEnum.text.name());
            }
            return false;
        }

        public boolean isAtMsg(){
            if(!CollectionUtils.isEmpty(this.message)){
                return this.message.stream().map(MessageHolder::getType).toList().contains(MessageHolderTypeEnum.at.name());
            }
            return false;
        }

        public boolean isAtBot(){
            return isAtQQ(String.valueOf(this.selfId));
        }

        public boolean isAtSelf(){
            return isAtQQ(String.valueOf(this.userId));
        }

        public boolean isAtQQ(String qq){
            return getAtQQs().contains(qq);
        }

        public List<String> getTexts(){
            if (isTextMsg()) {
                return this.message.stream().filter(e -> MessageHolderTypeEnum.text.name().equals(e.getType()))
                        .map(MessageHolder::getData)
                        .map(MessageData::getText)
                        .collect(Collectors.toList());
            }
            return Collections.emptyList();
        }

        public String getText(int index){
            List<String> texts = getTexts();
            if(CollectionUtils.isEmpty(texts)){
                return null;
            }
            if(index >= 0){
                try {
                    return texts.get(index);
                }catch (IndexOutOfBoundsException e){
                    return null;
                }
            }
            return StringUtils.join(texts,"");
        }

        public List<String> getPicUrls(){
            if(isPicMsg()){
                return this.message.stream().filter(e -> MessageHolderTypeEnum.image.name().equals(e.getType()))
                        .map(MessageHolder::getData)
                        .map(MessageData::getUrl)
                        .collect(Collectors.toList());
            }
            return Collections.emptyList();
        }

        public List<MessageData> getPicMessageData(){
            if(isPicMsg()){
                return this.message.stream().filter(e -> MessageHolderTypeEnum.image.name().equals(e.getType()))
                        .map(MessageHolder::getData)
                        .collect(Collectors.toList());
            }
            return Collections.emptyList();
        }

        public List<String> getReplyMsgIds(){
            if(isReplyMsg()){
                return this.message.stream().filter(e -> MessageHolderTypeEnum.reply.name().equals(e.getType()))
                        .map(MessageHolder::getData)
                        .map(MessageData::getId)
                        .collect(Collectors.toList());
            }
            return Collections.emptyList();
        }

        public List<String> getAtQQs(){
            if(isAtMsg()){
                return this.message.stream().filter(e -> MessageHolderTypeEnum.at.name().equals(e.getType()))
                        .map(MessageHolder::getData)
                        .map(MessageData::getQq)
                        .collect(Collectors.toList());
            }
            return Collections.emptyList();
        }

        /**
         * 获取图片路径
         * 从raw参数中获取图片本地路径
         * @param from 从哪里获取图片路径
         * @return
         */
        public List<String> getPicSourcePath(ElementTypeEnum from){
            if(from == ElementTypeEnum.PIC && isPicMsg()){
                List<PicElement> picElements = raw.getElements().stream().filter(e -> e.getElementType() == ElementTypeEnum.PIC.getType() && e.getPicElement() != null)
                        .map(Element::getPicElement).toList();
                return picElements.stream().map(PicElement::getSourcePath).collect(Collectors.toList());
            }
            if(from == ElementTypeEnum.REPLY && isReplyMsg() && !CollectionUtils.isEmpty(this.raw.getRecords())){
                List<String> picSourcePathList = new ArrayList<>();
                for (Record record : this.raw.getRecords()) {
                    if(CollectionUtils.isEmpty(record.getElements())){
                        continue;
                    }
                    // 从records中获取picElements 把picElements中的sourcePath取出来
                    List<String> collect = record.getElements().stream().filter(e -> e.getElementType() == ElementTypeEnum.PIC.getType() && e.getPicElement() != null)
                            .map(Element::getPicElement).map(PicElement::getSourcePath).toList();
                    picSourcePathList.addAll(collect);
                }
                return picSourcePathList;
            }
            return Collections.emptyList();
        }
}

